<?php
/**
* DIXon Generation 1 - JavaScript Client Pages
* 
* PHP Bindings for PHP 5.2.x and above
* 
* Copyright (c) 2008, Artem Ploujnikov
* All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided  that the following conditions are met:
* 
*  * Redistributions of source code must retain the above copyright notice, this 
*    list of conditions and the following disclaimer.
*  * Redistributions in binary form must reproduce the above copyright notice, this 
* 	 list of conditions and the following disclaimer in the documentation and/or 
*    other materials provided with the distribution.
* *  Neither the name of Artem Ploujnikov nor the names of the project's contributors 
* 	 may be used to endorse or promote products derived from this software without 
*    specific prior written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
* POSSIBILITY OF SUCH DAMAGE. 
*/

/**
* Represents a JavaScript Client Page
*
* @author Artem Ploujnikov  
*/
class JSClientPage {	
	/**
	* The extension used for script files
	*/
	const ScriptExtension = '.js';
	
	/**
	* The DiXon XSLT processor
	* 
	* @var XsltProcessor
	*/
	private $compiler;
	
	
	/**
	* The name of this page
	* 
	* @var string
	*/
	private $name;
	
	/**
	* The DiXon configuration instance used
	* for this page
	* 
	* @private DiXon_Conifguration
	*/
	private $configuration;
	
	
	/**
	* Creates a new client page
	* 
	* @param XsltProcessor $compiler an XSLT processor pre-loaded
	* 	with the DiXon compiler
	* 
	* @param string $name the name of the page
	*/
	public function __construct(XsltProcessor $compiler, $name, DiXon_Configuration $configuration = null) {
		
		$this->compiler = $compiler;
		$this->name = $name;
		
		if ($configuration === null) {
			$this->configuration = DiXon_Configuration::getInstance();
		} else {
			$this->configuration = $configuration;
		}
	}
	
	
	/**
	* Uses DiXon to compile this page
	*/
	public function compile() {
		$document = new DOMDocument();
		$document->load($this->getSourcePath());
		$compiledPath = $this->getCompiledPath();
		if (file_exists($compiledPath)) {
			if (!is_writable($compiledPath)) {
				throw new DiXon_FilePermissionDeniedException($compiledPath, $write);
			}
			unlink($compiledPath);
		}
		
		$compiledContent = $this->compiler->transformToXML($document);		
		file_put_contents($compiledPath, $compiledContent);
	}
	
	
	/**
	* Determines whether this page has already been
	* compiled
	* 
	* @return bool
	*/
	public function isUpToDate() {
		return $this->isCompiled() && !$this->isUpdated();	
	}
	
	/**
	* Determines whether this page has already been
	* compiled
	* 
	* @return bool
	*/
	public function isCompiled() {                       
		return file_exists($this->getCompiledPath());
	}
	
	/**
	* Determines whether the source is newer than the corresponding
	* compiled file
	* 
	* @return bool
	*/
	public function isUpdated() {
		$compiled_path = $this->getCompiledPath();
		$source_path = $this->getSourcePath();
		
		if (!file_exists($compiled_path) || !file_exists($source_path)) {
			$updated = null;
		} else {
			$compiled_mtime = filemtime($compiled_path);
			$source_mtime = filemtime($source_path);
			$updated = $compiled_mtime < $source_mtime;
		}
		
		return $updated;
	}
	
	/**
	* Determines the path to the page's source code
	* 
	* @return string
	*/
	public function getSourcePath() {
		return 
			DIXON_ROOT
			. DIRECTORY_SEPARATOR
			. $this->configuration->getValue(DiXon_Configuration::SourcePath) 
			. DIRECTORY_SEPARATOR 
			. DiXon_Configuration::toPath($this->name);				
	}
	
	
	/**
	* Determines the path to the compiled page.
	* 
	* @return string
	*/
	public function getCompiledPath() {
		return 
			DIXON_ROOT
			. DIRECTORY_SEPARATOR
			. $this->configuration->getPath(DiXon_Configuration::CompiledPath) 
			. DIRECTORY_SEPARATOR 
			. DiXon_Configuration::toPath($this->name)
			. self::ScriptExtension;				
	}
	
	/**
	* Checks whether the compiled path exists and attempts
	* to create any missiong directories.
	* 
	* @param string $path the path to check
	*/
	private function checkCompiledPath($path) {
		$fullPath = $this->configuration->getValue(DiXon_Configuration::CompiledPath);
		
		$pathComponents = explode(DIRECTORY_SEPARATOR, dirname($path));
		foreach($pathComponents as $pathComponent) {
			$fullPath .= DIRECTORY_SEPARATOR . $pathComponent;
			if (!is_dir($fullPath)) {
				if (file_exists($fullPath)) {
					throw new DiXon_WrongFileTypeException(
						$fullPath,
						DiXon_FileType::File,
						DiXon_FileType::Directory						
					);
				}
				
				$result = mkdir($fullPath);
				if (!$result) {
					throw new DiXon_CreateFileException(
						$fullPath, 
						DiXon_FileType::Directory
					);
				}
			}
		}
	}
	
	
	/**
	* Writes this JavaScript client page to an output
	* stream
	* 
	* @param IOutputStream $stream the destination stream
	*/
	public function output(IOutputStream $stream) {
		$sourcePath = $this->getSourcePath();
		if (!file_exists($sourcePath)) {
			throw new DiXon_FileNotFoundException($sourcePath);
		}
		if (!is_readable($sourcePath)) {
			throw new DiXon_FilePermissionDeniedException(
				$sourcePath, 
				DiXon_Permission::Read
			);
		}
		if (!$this->isUpToDate()) {
			$this->compile();
		}
		$path = $this->getCompiledPath();
		if (!file_exists($path)) {
			throw new DiXon_FileNotFoundException($path);
		}
		
		if (is_dir($path)) {
			throw new DiXon_WrongFileTypeException(
				$path,
				DiXon_FileType::Directory,
				DiXon_FileType::File
			);
		}
		
		if (!is_readable($path)) {
			throw new DiXon_FilePermissionDeniedException(
				$path, 
				DiXon_Permission::Read
			);
		}
		$contents = file_get_contents($path);
		$stream->write( 
			file_get_contents($path)
		);
	}

}


?>